﻿using FollowMe.Infrastructure;
using FollowMe.Infrastructure.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

/**
 * FollowMe Server
 * UWRF CS425 & CS343 Project Fall 2014
 * Adam Drews
 *   email adam.drews@my.uwrf.edu
 * Tyler Johnson
 *   email tyler.johnson@my.uwrf.edu
 * Nicholas Thorp
 *   email nicholas.thorp@my.uwrf.edu
 */
namespace FollowMe.Repository
{
    /// <summary>
    /// A Generic Repository for use with a DBContext, Sets
    /// </summary>
    /// <typeparam name="T">A concrete class of type IAggregateRoot</typeparam>
    /// <typeparam name="TKey">The type of the key (from the DB. In our case they are all GUIDs).</typeparam>
    public abstract class Repository<T, TKey> : IDisposable, IUnitOfWorkRepository where T : class, IAggregateRoot, IDisposable
    {
        /// <summary>
        /// The fmcontext=DBContext
        /// </summary>
        private IContext fmcontext;

        /// <summary>
        /// Initializes a new instance of the <see cref="Repository{T, TKey}"/> class.
        /// </summary>
        /// <param name="_fm">The _FM.</param>
        public Repository(IContext _fm)
        {
            fmcontext = _fm;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Repository{T, TKey}"/> class.
        /// </summary>
        public Repository() { }

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Add(T entity)
        {
            fmcontext.getSet<T>().Add(entity);
        }

        /// <summary>
        /// Removes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Remove(T entity)
        {
            if (fmcontext.isDetached(entity))
            {
                fmcontext.getSet<T>().Attach(entity);
            }
            fmcontext.getSet<T>().Remove(entity);
        }

        /// <summary>
        /// Removes all entities in a collection.
        /// </summary>
        /// <param name="list">The list.</param>
        public void RemoveAll(IEnumerable<T> list)
        {
            foreach(T t in list)
            {
                Remove(t);
            }
        }

        /// <summary>
        /// Saves the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Save(T entity)
        {
            fmcontext.getSet<T>().Attach(entity);
            fmcontext.markModified<T>(entity);
        }

        /// <summary>
        /// Gets the object set.  For a DBContext these are DBsets/Tables in the DB.
        /// </summary>
        /// <returns></returns>
        public IDbSet<T> GetObjectSet()
        {
            return fmcontext.getSet<T>();
        }

        /// <summary>
        /// Gets the name of the entity set: the DB Table name.
        /// </summary>
        /// <returns></returns>
        public string GetEntitySetName()
        {
            return typeof(T).Name;
        }

        /// <summary>
        /// Finds the entity by ID.
        /// </summary>
        /// <param name="Id">The identifier.</param>
        /// <returns></returns>
        public virtual T FindBy(TKey Id){
            return GetObjectSet().Find(Id);
        }

        /// <summary>
        /// Finds all entities in a set.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> FindAll()
        {
            return GetObjectSet().ToList<T>();
        }

        /// <summary>
        /// Finds all.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <param name="count">The count.</param>
        /// <returns></returns>
        public IEnumerable<T> FindAll(int index, int count)
        {
            return GetObjectSet().Skip(index).Take(count).ToList<T>();
        }

        public virtual void PersistCreationOf(IAggregateRoot entity)
        {
           //DBSet tracks UoW
            ;
        }

        public void PersistUpdateOf(IAggregateRoot entity)
        {
            //DBSet tracks UoW
            ;
        }

        public void PersistDeletionOf(IAggregateRoot entity)
        {
            //DBSet tracks UoW
            ;
        }

        /// <summary>
        /// Disposes the specified disposing.
        /// </summary>
        /// <param name="disposing">if set to <c>true</c> [disposing].</param>
        protected virtual void Dispose(Boolean disposing)
        {

        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}
